/// 
/// MaDAson - Toolkit for Model Driven Software Development
/// 
/// Copyright [2006] Marcus Lankenau
/// 
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///  
///     http://www.apache.org/licenses/LICENSE-2.0
///  
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
/// 

using System;
using System.Configuration;
using System.IO;
using Madason.MetaModel;
using Madason.MetaModel.DAO;
using Madason.MetaModel.Interfaces;
using System.Xml;
using System.Reflection;
using Madason.MetaModel.Validation;
using Madason.GenUtils;

/// <summary>
/// Summary description for Program
/// </summary>
public class Program
{
	protected const string TEST_PATH = "tests";

	static GeneratorWorkflow workflow;

	/// <summary>
	/// generate ddl script
	/// </summary>
	/// <param name="model"></param>
	/// <param name="argMap"></param>
	public static void GenerateDdl(Madason.MetaModel.Model model, System.Collections.Generic.Dictionary<string, string> argMap)
	{
		using (System.IO.StreamWriter writer = new System.IO.StreamWriter("ddl.sql"))
		{
			DDL ddl = new DDL();
			ddl.Model = model;
			//ddl.DBMapper = new DBMapperSqlserver();
			ddl.Render(writer);
		}
	}

	/// <summary>
	/// generate data access objects
	/// </summary>
	/// <param name="classes"></param>
	/// <param name="argMap"></param>
	public static void GenerateDao(Madason.MetaModel.ClassList classes, System.Collections.Generic.Dictionary<string, string> argMap)
	{
		string daoPath = argMap["daopath"];
		string dtoPath = argMap["dtopath"];
		
		foreach (Class cls in classes)
		{
			Console.WriteLine("processing " + cls.ExplicitName);
			if (cls.Stereotype == Stereotype.Enum)
			{
				Enumeration enumeration = new Enumeration();
				string path = cls.Namespace.CreateDirectory(dtoPath).FullName + "\\" + cls.Name + ".java";
				SensorWriter writer = new SensorWriter(path);
				enumeration.Class = cls;
				enumeration.Render(writer);
				writer.Close();
			}
			if (cls.StereotypeName == "Procedures")
			{
				Console.WriteLine("  generating abstract dao");
				ProceduresAbstract daoAbstract = new ProceduresAbstract();
				string path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "Access.java";
				using (SensorWriter writer = new SensorWriter(path))
				{
					daoAbstract.Class = cls as ProcedureContainer;
					daoAbstract.Render(writer);
				}

				Console.WriteLine("  generating dao impl");
				ProceduresImpl daoImpl = new ProceduresImpl();
				path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "Access" + Context.DatabaseStrategy.GetClassSuffix() + ".java";
				using (SensorWriter writer = new SensorWriter(path))
				{
					daoImpl.Class = cls as ProcedureContainer;
					daoImpl.Render(writer);
				}
			}

			if (cls.Stereotype == Stereotype.Entity ||
				cls.Stereotype == Stereotype.Boundary)
			{
				Console.WriteLine("  generating transfer object");
				TransferObject transferObject = new TransferObject();
				string path = cls.Namespace.CreateDirectory(dtoPath).FullName + "\\" + cls.Name + ".java";
				ProtectedSections sections = new ProtectedSections();
				sections.Load(new FileInfo(path));

				using (SensorWriter writer = new SensorWriter(path))
				{
					transferObject.Class = cls as Entity;
					transferObject.ProtectedSection = sections;
					transferObject.Render(writer);
				}


				if (cls.Stereotype == Stereotype.Entity)
				{					



					Console.WriteLine("  generating abstract dao");
					DaoAbstract daoAbstract = new DaoAbstract();
					path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "Access.java";
					using (SensorWriter writer = new SensorWriter(path))
					{
						daoAbstract.Class = cls as Entity;
						daoAbstract.UseGenerics = !argMap.ContainsKey("useGenerics") || argMap["useGenerics"] == "yes";
						daoAbstract.Render(writer);
					}

					Console.WriteLine("  generating dao impl");
					if (workflow.GetBoolParam("genSqlServer"))
					{
						Context.DatabaseStrategy = new SqlServerStrategy();
						DaoImpl daoImpl = new DaoImpl();
						path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "AccessSqlServer.java";
						using (SensorWriter writer = new SensorWriter(path))
						{
							daoImpl.Class = cls as Entity;
							daoImpl.UseGenerics = !argMap.ContainsKey("useGenerics") || argMap["useGenerics"] == "yes";
							daoImpl.Render(writer);
						}
					}

					if (argMap.ContainsKey("ibatisConfigDir"))
					{
						Console.WriteLine("  generating ibatis dao");
						Context.DatabaseStrategy = new IBatisStrategy();
						IBatisSqlMap sqlMap = new IBatisSqlMap();
						path = cls.Namespace.CreateDirectory(argMap["ibatisConfigDir"]).FullName + "\\" + cls.Name + ".xml";
						sections = new ProtectedSections();
						sections.Load(new FileInfo(path));
						using (SensorWriter writer = new SensorWriter(path))
						{
							sqlMap.ProtectedSection = sections;
							sqlMap.Class = cls as Entity;							
							sqlMap.Render(writer);
						}
					}

					if (workflow.GetBoolParam("genOracle"))
					{
						Context.DatabaseStrategy = new OracleStrategy();
						DaoImpl daoImpl = new DaoImpl();
						path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "AccessOracle.java";
						using (SensorWriter writer = new SensorWriter(path))
						{
							daoImpl.Class = cls as Entity;
							daoImpl.UseGenerics = !argMap.ContainsKey("useGenerics") || argMap["useGenerics"] == "yes";
							daoImpl.Render(writer);
						}
					}

					if (workflow.GetBoolParam("genIBatis"))
					{
						DaoImplIBatis ibatisImpl = new DaoImplIBatis();
						path = cls.Namespace.CreateDirectory(daoPath).FullName + "\\" + cls.Name + "AccessIBatis.java";
						using (SensorWriter writer = new SensorWriter(path))
						{
							ibatisImpl.Class = cls as Entity;
							ibatisImpl.Render(writer);
						}
					}
					
					if (argMap.ContainsKey(TEST_PATH))
					{
						Console.WriteLine("  generating test");
						DaoTest daoTest = new DaoTest();
						path = cls.Namespace.CreateDirectory(argMap[TEST_PATH]).FullName + "\\" + cls.Name + "Test.java";
						using (SensorWriter writer = new SensorWriter(path))
						{
							daoTest.Class = cls as Entity;
							daoTest.Render(writer);
						}
					}
				}
			}
		}
	}

	/// <summary>
	/// main function
	/// - parse command argumends
	/// - invoke special generator-functions
	/// </summary>
	/// <param name="args"></param>
	[STAThread]
	public static int Main(string[] args)
	{
		workflow = new GeneratorWorkflow(args);

		workflow.AddParameterDefinition("daopath", ParameterType.Directory, "target directory for dao objects", true);
		workflow.AddParameterDefinition("dtopath", ParameterType.Directory, "target directory for dto objects", true);
		workflow.AddParameterDefinition("ibatisConfigDir", ParameterType.Directory, "target directory for ibats config-files", false);
		workflow.AddParameterDefinition("genOracle", ParameterType.Bool, "generate oracle dao implementation", false);
		workflow.AddParameterDefinition("genSqlServer", ParameterType.Bool, "generate sql server dao implementation", false);
		workflow.AddParameterDefinition("genIBatis", ParameterType.Bool, "generate ibatis dao implementation", false);
		workflow.AddParameterDefinition("useGenerics", ParameterType.Bool, "use generics for list-types", false);
		
		workflow.CheckCommandLine();
		workflow.LoadModel();
		workflow.Transform();
		workflow.Validate();



        Context.TargetLanguage = TargetLanguages.Java;

		Model model = workflow.Model;

		
		//
		// Generate sources
		//
		ClassList classesToGenerate = model.DeepGetClasses().Filter(Stereotype.Entity);
		classesToGenerate.AddRange(model.DeepGetClasses().Filter(Stereotype.Enum));
		classesToGenerate.AddRange(model.DeepGetClasses().Filter(Stereotype.Boundary));
		classesToGenerate.AddRange(model.DeepGetClasses().Filter("Procedures"));
		GenerateDao(classesToGenerate, workflow.Arguments);

		Console.WriteLine("gen ddl");
		GenerateDdl(model, workflow.Arguments);
		return 0;
	}
}
